/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jboss.seam.scxml.impl.context;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.scxml.Context;
import org.apache.commons.scxml.SCXMLExecutor;
import org.apache.commons.scxml.env.SimpleContext;
import org.apache.commons.scxml.model.State;
import org.apache.commons.scxml.model.TransitionTarget;
import org.jboss.seam.scxml.StateScoped;
import org.jboss.seam.scxml.impl.DialogUtils;
import org.jboss.weld.context.AbstractContext;
import org.jboss.weld.context.api.ContextualInstance;
import org.jboss.weld.context.beanstore.BeanStore;

/**
 *
 * @author Waldemar Kłaczyński
 */
public class StateContextImpl extends AbstractContext {

    public StateContextImpl() {
        super(true);
    }

    private SCXMLExecutor getExecutor() {
        return DialogUtils.getExecutor();
    }

    private Context getContext() {
        SCXMLExecutor executor = getExecutor();
        if (executor == null) {
            return null;
        }
        Iterator iterator = executor.getCurrentStatus().getStates().iterator();
        State state = ((State) iterator.next());
        Context context = getContext(state);
        return context;
    }

    public Context getContext(final TransitionTarget transitionTarget) {
        SCXMLExecutor executor = getExecutor();
        if (executor == null) {
            return null;
        }
        Map<TransitionTarget, Object> contexts = getContexts();
        Context context = (Context) contexts.get(transitionTarget);
        if (context == null) {
            TransitionTarget parent = transitionTarget.getParent();
            if (parent == null) {
                context = new SimpleContext(executor.getRootContext());
            } else {
                context = new SimpleContext(getContext(parent));
            }
            contexts.put(transitionTarget, context);
        }
        return context;
    }

    private Map<TransitionTarget, Object> getContexts() {
        SCXMLExecutor executor = getExecutor();
        if (executor == null) {
            return null;
        }
        Context context = executor.getRootContext();


        Map<TransitionTarget, Object> instance = (Map<TransitionTarget, Object>) context.get("_____@@@SopeStateMap____");
        if (instance == null) {
            instance = Collections.synchronizedMap(new HashMap<TransitionTarget, Object>());
            context.set("_____@@@SopeStateMap____", instance);
        }
        return instance;
    }

    @Override
    public boolean isActive() {
        return getExecutor() != null;
    }

    @Override
    protected BeanStore getBeanStore() {
        return new StateBeanStore();
    }

    @Override
    public Class<? extends Annotation> getScope() {
        return StateScoped.class;
    }

    class StateBeanStore implements BeanStore {

        @Override
        public <T> ContextualInstance<T> get(String id) {
            return (ContextualInstance<T>) getContext().get(id);
        }

        @Override
        public boolean contains(String id) {
            Context context = getContext();
            if (context == null) {
                return false;
            }
            return getContext().has(id);
        }

        @Override
        public void clear() {
        }

        @Override
        public Iterator<String> iterator() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public <T> void put(String id, ContextualInstance<T> contextualInstance) {
            getContext().set(id, contextualInstance);
        }
    }
}
